package com.classLoader;

import java.io.*;

/**
 * 自定义类加载器测试
 */
public class MyClassLoaderTest {

    public static void main(String[] args) throws Exception {
        MyClassLoader msbClassLoader = new MyClassLoader("D:\\DownLoadProject\\LearnJVM\\testData\\");
        Class clazz1 = msbClassLoader.loadClass("com.test.LoadTestClass");
        Object o1 = clazz1.newInstance();
        System.out.println(clazz1.getClassLoader());
        System.out.println(clazz1.hashCode());

        msbClassLoader = null;

        //如果不重写loadClass方法，并且父类加载器可以加载到，那么这里还是会委托给其父类加载器AppClassLoader加载
        msbClassLoader = new MyClassLoader("D:\\DownLoadProject\\LearnJVM\\testData\\");
        Class clazz2 = msbClassLoader.loadClass("com.test.LoadTestClass");
        //一个加载器对象不能反射另一个加载器对象newInstance出来的实例对象，这也从侧面证明了系统类加载器是单例的
        //下面报错：Exception in thread "main" java.lang.IllegalArgumentException: object is not an instance of declaring class
//        clazz2.getMethod("test").invoke(o1);
        System.out.println(clazz2.getClassLoader());
        System.out.println(clazz2.hashCode());

        System.out.println(clazz1 == clazz2);
    }

    public static class MyClassLoader extends ClassLoader{

        private String myClassFilePath;

        MyClassLoader(String myClassFilePath) {
            this.myClassFilePath = myClassFilePath;
        }

        @Override
        public Class<?> loadClass(String name) throws ClassNotFoundException {
            System.out.println("MyClassLoader: 我来过，我委托给上级了"+name);
            return super.loadClass(name);
        }

        @Override
        protected Class<?> findClass(String classCompleteName) throws ClassNotFoundException {
            System.out.println("MyClassLoader尝试加载"+classCompleteName);
            byte[] result = getClassFromCustomPath(myClassFilePath+classCompleteName.replace(".", File.separator)+".class");
            if (result == null) {
                throw new ClassNotFoundException(classCompleteName);
            } else {
                return defineClass(classCompleteName, result, 0, result.length);
            }
        }

        private byte[] getClassFromCustomPath(String classFilePath) {
            File f = new File(classFilePath);
            InputStream is = null;
            try {
                //读取编译后的文件
                is = new FileInputStream(f);
                byte[] bytes=new byte[is.available()];
                is.read(bytes);
                return bytes;
            } catch (Exception e){

            } finally {
                try {
                    if (is != null) {
                        is.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return null;
        }
    }
}
